﻿// --------------------------------------------------------------------------------------------------------------------
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
// --------------------------------------------------------------------------------------------------------------------

namespace WP7Contrib.View.Controls.Extensions
{
    using System;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;

    using Microsoft.Phone.Controls;

    public enum Theme
    {
        /// <summary>
        /// Theme light
        /// </summary>
        Light,

        /// <summary>
        /// Theme dark
        /// </summary>
        Dark
    }

    public static class ApplicationExtensions
    {
        private const string PhoneLightThemeVisibility = "PhoneLightThemeVisibility";

        private static bool listeningToNavEvents;
        private static bool isNavigating;

        /// <summary>
        /// Gets the theme.
        /// </summary>
        /// <param name="application">The application.</param>
        /// <returns></returns>
        public static Theme GetTheme(this Application application)
        {
            var visibility = (Visibility)Application.Current.Resources[PhoneLightThemeVisibility];
            return (visibility == Visibility.Visible) ? Theme.Light : Theme.Dark;
        }

        /// <summary>
        /// Determines whether [is design time] [the specified application].
        /// </summary>
        /// <param name="application">The application.</param>
        /// <returns>
        /// <c>true</c> if [is design time] [the specified application]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsDesignTime(this Application application)
        {
            return DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual);
        }

        /// <summary>
        /// Goes the back.
        /// </summary>
        /// <param name="application">The application.</param>
        public static void GoBack(this Application application)
        {
            var frame = application.RootVisual as PhoneApplicationFrame;
            EnsureListeningToNaviation(frame);

            if (frame == null)
            {
                return;
            }

            if (isNavigating)
            {
                return;
            }
            
            if (frame.CanGoBack)
            {
                frame.GoBack();
            }
        }

        /// <summary>
        /// Goes the forward.
        /// </summary>
        /// <param name="application">The application.</param>
        public static void GoForward(this Application application)
        {
            var frame = application.RootVisual as PhoneApplicationFrame;
            EnsureListeningToNaviation(frame);

            if (frame == null)
            {
                return;
            }

            if (isNavigating)
            {
                return;
            }

            if (frame.CanGoForward)
            {
                frame.GoForward();
            }
        }

        /// <summary>
        /// Navigates the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        /// <param name="uri">The URI.</param>
        public static void Navigate(this Application application, Uri uri)
        {
            var frame = application.RootVisual as PhoneApplicationFrame;
            EnsureListeningToNaviation(frame);

            //System.Diagnostics.Debug.WriteLine(string.Format("Navigating in App Extension. Frame Content: {0}, Current Source: {1}, Target: {2}, IsNavigating: {3}", frame.Content.GetType().ToString(), frame.CurrentSource, uri, _isNavigating));

            if (frame == null)
            {
                return;
            }

            if (uri == null)
            {
                return;
            }

            if (uri.OriginalString == frame.CurrentSource.OriginalString)
            {
                return;
            }

            if (isNavigating)
            {
                //System.Diagnostics.Debug.WriteLine("Cancelling nav b/c we're currently navigating");
                return;
            }

            //System.Diagnostics.Debug.WriteLine("Calling frame.nav");
            frame.Navigate(uri);
        }

        /// <summary>
        /// Navigates the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        /// <param name="uri">The URI.</param>
        public static void Navigate(this Application application, string uri)
        {
            Navigate(application, new Uri(uri, UriKind.Relative));
        }

        /// <summary>
        /// Navigates the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        /// <param name="uri">The URI.</param>
        /// <param name="context">The context.</param>
        public static void Navigate(this Application application, string uri, object context)
        {
            var root = Application.Current.RootVisual as FrameworkElement;
            if (root != null)
            {
                root.DataContext = context;
            }

            Navigate(application, new Uri(uri, UriKind.Relative));
        }

        /// <summary>
        /// Navigates the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        /// <param name="uri">The URI.</param>
        /// <param name="context">The context.</param>
        public static void Navigate(this Application application, Uri uri, object context)
        {
            var root = Application.Current.RootVisual as FrameworkElement;
            if (root != null)
            {
                root.DataContext = context;
            }

            Navigate(application, uri);
        }

        /// <summary>
        /// Ensures the listening to naviation.
        /// </summary>
        /// <param name="frame">The frame.</param>
        private static void EnsureListeningToNaviation(PhoneApplicationFrame frame)
        {
            if (listeningToNavEvents)
            {
                return;
            }

            frame.Navigating += (sender, e) => isNavigating = true;
            frame.Navigated += (sender, e) => isNavigating = false;
            frame.NavigationStopped += (sender, e) => isNavigating = false;
            frame.NavigationFailed += (sender, e) => isNavigating = false;
            listeningToNavEvents = true;
        }

        /// <summary>
        /// Gets the active page.
        /// </summary>
        /// <param name="application">The application.</param>
        /// <returns></returns>
        public static PhoneApplicationPage GetActivePage(this Application application)
        {
            PhoneApplicationPage content = null;
            if (application != null)
            {
                var rootVisual = application.RootVisual as PhoneApplicationFrame;
                if (rootVisual != null)
                {
                    content = rootVisual.Content as PhoneApplicationPage;
                }
            }

            return content;
        }


        /// <summary>
        /// Returns the first instance of a type implementing T from the Application's 
        /// ApplicationLifetimeObjects list, or null if one cannot be found.
        /// </summary>
        /// <typeparam name="T">
        /// The service's type.
        /// </typeparam>
        /// <param name="application">
        /// </param>
        /// <returns>
        /// The get service.
        /// </returns>
        public static T GetService<T>(this Application application)
        {
            return application.ApplicationLifetimeObjects.OfType<T>().FirstOrDefault();
        }
    }
}
